﻿; myHotStrings
; Author: PreZ!dent
;
#SingleInstance force
#Include LVA.ahk
#Include inc\str.ahk
#include inc\lang.ahk
#include inc\funx.ahk
gosub readini
gosub iniString

;====localized string assignment end=====

;#IncludeAgain inc\str.ahk
ver=1.0
;#NoTrayIcon
;; TO DO
;MsgBox % A_IsUnicode ? "Unicode" : "ANSI"

;=====init start=====
DetectHiddenWindows On  ; Allows a script's hidden main window to be detected.
SetTitleMatchMode 2  ; Avoids the need to specify the full path of the file below.
WinClose kv.ahk - AutoHotkey  ; Update this to reflect the script's name (case sensitive).

if splashimg and !ifreload
{
  SplashImage ,init.gif, B
  ;PostMessage, 0x111, 65305,,, kv.ahk - AutoHotkey  ; Suspend.
  sleep 1000
  SplashImage Off
}

IfNotExist kv.dat 
  FileAppend, ahk`tAutoHotKey`nms`tMicrosoft`n, kv.dat, utf-16

kvTable := Object()

FileRead, f1, kv.dat 
StringReplace,OutputVar,f1,`n,`n,useerrorlevel 
Lines:=ErrorLevel + 1 
;MsgBox, % lines


loop, read, kv.dat
{
  pgr:=Round(A_Index/Lines*100)
  Progress %pgr%
  Stringsplit, kvA, A_LoopReadLine, %A_Tab%
  ;kvTable[kvA1] := kvA2 ver 0.1
  if IsObject(kvTable[kvA1])
  {
    kvTable[kvA1].Insert(kvA2)
    kvTable[kvA1] := dedup(kvTable[kvA1])
   ;tooltip, % "..." kvTable[kvA1].2
  }
  else
  {
    kvTable[kvA1] := Array(kvA2)
  ;  MsgBox, notifobject
  }
}
progress off

gosub makeScript

if traytip and !ifreload
{
  traytip , %TrayTip_Title%, %Traytip_text%, 5, 1
}
;=====init end=====

;=====creat gui start=====
Menu, FileMenu, Add, %Reload%, Reload
menu, FileMenu, add
Menu, FileMenu, Add, %Exit%, FileExit
Menu, MyMenuBar, add, %File%, :FileMenu

for k, v in Langs
{
 ; MsgBox, %v%
  Menu, LangMenu, add, %v%, ChangeLang
}
chkd := Langs[lang]
;MsgBox % chkd
menu, LangMenu, Check, %chkd%
Menu, MyMenuBar, Add, %Language%, :LangMenu
Menu, PrefMenu, Add, %Settings%, Settings
Menu, MyMenuBar, Add, %Preferences%, :PrefMenu
Menu, HelpMenu, Add, %About%, HelpAbout
Menu, MyMenuBar, Add, %Help%, :HelpMenu

Gui, Menu, MyMenuBar
Gui, Add, Text, x30 y10 w40 h20 , %Key%
Gui, Add, Edit, x70 y8 w75 h20 r1 vkEdit,  
Gui, Add, Text, x150 y10 w50 h20 , %Text%
Gui, Add, Edit, x200 y8 w190 h20 r1 vvEdit, 
;gui, add, Edit, x1 y1 w0 h0 r1 vid,
Gui, Add, Button, x395 y08 w20 h20 gAddKV vbuttonAdd +Default, &+
gui, add, button, x420 y8 w25 h20 gWriteScriptAndRun vbuttonRun, &OK
Gui, Add, ListView, x30 y30 r100 w400 h350 gUpdDelKV vKVLv AltSubmit grid BackgroundWhite caa0000, %Key_Text%
gui, add, Text, x30 y385 w400 h30, %tips%
Gui, Add, StatusBar


gosub populateLV
LV_ModifyCol(1, 50)
LV_ModifyCol(2, 350)
LV_ModifyCol(3,0)

Gui, color, efefef
;Gui, Show, Center h400 w460, %myHotStrings_Manager%
;gui,1: hide
OnMessage(0x200, "WM_MOUSEMOVE")
;Return

LVA_ListViewAdd("KVLv", "AR")
OnMessage("0x4E", "LVA_OnNotify")
LVA_ListViewModify("KVLv", "RB0xDDDDFF RFBlack")
LVA_Refresh("KVLv")
gosub makeScript
Return

readini:
IniRead, lang, pref.ini, Pref, lang
iniRead, sound, pref.ini, Pref, sound
IniRead, trigger, pref.ini, Pref, trigger
iniRead, splashimg, pref.ini, Pref, splashimg
iniRead, traytip, pref.ini, Pref, traytip
iniRead, ifreload, pref.ini, Pref, ifreload
iniRead, vtab, pref.ini, Pref, vtab
iniRead, vspace, pref.ini, Pref, vspace
iniRead, venter, pref.ini, Pref, venter
iniRead, custkey, pref.ini, Pref, custkey
trigger := TAB%vtab% . SPACE%vspace% . ENTER%venter% . custkey
iniRead, sendmode, pref.ini, Pref, sendmode
if sendmode = P
{ 
  cb = 1
  si = 0
}
else sendmode = S
{
  cb = 0
  si = 1
}
return

;====localized string assignment start=====
iniString:
confirm_update := confirm_update_%lang%
already_exist_pairs := already_exist_pairs_%lang%
added_at := added_at_%lang%
updated_at := updated_at_%lang%
deleted_at := deleted_at_%lang%
key_empty := key_empty_%lang%
text_empty := text_empty_%lang%
Update_or_Delete := Update_or_Delete_%lang%
kEdit_TTip := kEdit_TTip_%lang%
vEdit_TTip := vEdit_TTip_%lang%
KVlv_TTip := KVlv_TTip_%lang%
buttonAdd_TTip := buttonAdd_TTip_%lang%
buttonRun_TTip := buttonRun_TTip_%lang%
myHotStrings_Manager := myHotStrings_Manager_%lang%
Key_Text := Key_Text_%lang%
TrayTip_text := TrayTip_text_%lang%
Traytip_title := Traytip_title_%lang%
Traytip_suspended_title := Traytip_suspended_title_%lang%
traytip_suspended_text := traytip_suspended_text_%lang%
Key := Key_%lang%
Text := Text_%lang%
tips := tips_%lang%
Update := Update_%lang%
Delete := Delete_%lang%
Cancel := Cancel_%lang%
myHotStrings := myHotStrings_%lang%
Exit := Exit_%lang%
File := File_%lang%
About := About_%lang%
Help := Help_%lang%
Language := Language_%lang%
Reload := Reload_%lang%
Settings := Settings_%lang%
Preferences := Preferences_%lang%
Show_Startup_image := Show_Startup_image_%lang%
Show_Starup_Traytip := Show_Starup_Traytip_%lang%
Play_Sound := Play_Sound_%lang%
Trigger_Key := Trigger_Key_%lang%
Tab := Tab_%lang%
Space := Space_%lang%
Enter := Enter_%lang%
Customized := Customized_%lang%
OK := OK_%lang%
Settings_Title := Settings_Title_%lang%
What_is_Trigger_Key := What_is_Trigger_Key_%lang%
Custkey_TTip := Custkey_TTip_%lang%
wait_loading := wait_loading_%lang%
Send_Mode := Send_Mode_%lang%
Clip_Board :=Clip_Board_%lang%
Send_Input :=Send_Input_%lang%
return


WriteScriptAndRun:
GuiEscape:
GuiClose:
Gui, 1:hide
;msgbox, 0000000
Gosub makeScript
return

Reload:
  IniWrite, 1, pref.ini, Pref, ifreload
  Reload
return ;reload

Settings:
  Gui,3: Add, GroupBox, x16 y7 w440 h410 , %Preferences%
  Gui,3: Add, CheckBox, x45 y118 w380 h30 vsplashimg Checked%splashimg%, %Show_Startup_image%
  Gui,3: Add, CheckBox, x45 y158 w380 h30 vtraytip checked%traytip%, %Show_Starup_Traytip%
  Gui,3: Add, CheckBox, x45 y198 w380 h30 vsound checked%sound%, %Play_Sound%
  Gui,3: Add, GroupBox, x45 y248 w380 h120 , %Trigger_Key%
  Gui,3: Add, Text, x65 y268 w350 h30 vdummy, %What_is_Trigger_Key%
  Gui,3: Add, CheckBox, x65 y298 w80 h30 vvtab checked%vtab%, %Tab%
  Gui,3: Add, CheckBox, x175 y298 w90 h30 vvspace checked%vspace%, %Space%
  Gui,3: Add, CheckBox, x275 y298 w100 h30 vventer checked%venter%, %Enter%
  Gui,3: Add, Text, x65 y338 w90 h20 , %Customized%
  Gui,3: Add, Edit, x155 y338 w230 h20 vcustkey, %custkey% 
  Gui,3: Add, Button, x85 y375 w100 h30 g3buttonOK vbuttonOK, %OK%
  Gui,3: Add, Button, x275 y375 w100 h30 g3buttonCancel vbuttonCancel, %Cancel%
  Gui,3: Add, GroupBox, x46 y37 w380 h70 , %Send_Mode%
  Gui,3: Add, Radio, x58 y58 w360 h20 vcb checked%cb%, %Clip_Board%
  Gui,3: Add, Radio, x58 y83 w360 h20 vsi checked%si%, %Send_Input%
  gui,3:+Owner
  Gui +disabled
  Gui,3: Show, Center h433 w477, %Settings_Title%
return ;settings

3buttonOK:
  Gui,3:submit 
  gui,1:-disabled
  gui,3:destroy
  IniWrite, %splashimg%, pref.ini, Pref, splashimg
  iniWrite, %sound%, pref.ini, Pref, sound
  IniWrite, %traytip%, pref.ini, Pref, traytip
  IniWrite, %vtab%, pref.ini, Pref, vtab
  IniWrite, %vspace%, pref.ini, Pref, vspace
  IniWrite, %venter%, pref.ini, Pref, venter
  IniWrite, %custkey%, pref.ini, Pref, custkey
  trigger := TAB%vtab% . SPACE%vspace% . ENTER%venter% . custkey
  sendmode := si?"S":"P"
  IniWrite, %sendmode%, pref.ini, Pref, sendmode
  gosub makeScript
  gui,1:show
return

3buttonCancel:
3GuiClose:
3GuiEscape:
  gui,1:-disabled
  gui,3:destroy
return


ChangeLang:
  StringSplit ,lang, A_ThisMenuItem, %A_Tab%
  ;lang := lang2
  IniWrite, %lang2%, pref.ini, Pref, lang
;  langfilepath := "inc\str_" . lang2 . ".ahk"
;  FileCopy, %langfilepath%, inc\str.ahk, 1
  IniWrite, 1, pref.ini, Pref, ifreload
  Reload
  ;gosub iniString
return ;changelang


FileExit:
 WinClose kv.ahk - AutoHotkey
 IniWrite, 0, pref.ini, Pref, ifreload
 ExitApp
return ;fileexit

HelpAbout:
  Gui, 8:+owner1  ; Make the main window (Gui #1) the owner of the "about box" (Gui #2).
  Gui +Disabled  ; Disable main window.
  gui, 8:Add, Text,, %myHotStrings% %ver%
  Gui, 8:Add, Text,, Author: PreZ!dent`nFeedback: cpen98@gmail.com
  Gui, 8:Add, Button,  w80 h20 x20 Default, OK
  Gui, 8:Show
return ; HelpAbout

8ButtonOK:
8GuiClose:
8GuiEscape:
Gui, 1:-Disabled
Gui Destroy
return

UpdDelKV:
  if A_GuiEvent = DoubleClick
  {
    LV_GetText(kEdit, A_EventInfo, 1)
    LV_GetText(vEdit, A_EventInfo, 2)
    LV_GetText(id, A_EventInfo, 3)
    Gui, 5:Add, Edit, x16 y17 w140 h20 vkEdit, %kEdit%
    Gui, 5:Add, Edit, x16 y37 w370 h20 vvEdit, %vEdit%
    gui, 5:add, Edit, x1 y1 w0 h0 vid, %id%
    Gui, 5:Add, Button, x26 y67 w100 h30 g5updKV, %Update%
    Gui, 5:Add, Button, x136 y67 w110 h30 g5delKV, %Delete%
    gui, 5:add, button, x256 y67 w110 h30 g5cancel, %Cancel%
    gui, 5:+Owner1
    Gui +Disabled
    Gui, 5:Show, w411 h118, %Update_or_Delete% %kEdit% = %vEdit%
    ;prv_key = %kEdit%
  }
  if A_GuiEvent = Normal
  {
    LV_GetText(kEdit, A_EventInfo, 1)
    LV_GetText(vEdit, A_EventInfo, 2)
    LV_GetText(id, A_EventInfo, 3)
    GuiControl ,,kEdit, %kEdit%
    GuiControl ,,vEdit, %vEdit%
    GuiControl ,,id, %id%
  }
return ;UpdDelKV

addKV:
gui, submit, nohide
  if  kEdit =
  {
    ControlFocus , Edit1
    msgbox % key_empty
    return 
  }
  if vEdit =
  {
    ControlFocus , Edit2
	msgbox % text_empty
    return
  }
  ;; modi needed......
 /* if kvTable[kEdit]
  {
    MsgBox ,  36, %confirm_update%, %already_exist_pairs%
    IfMsgBox Yes
	{
	  gosub updKV ; need update
	}
	else
	{
      return
	}
  }
  else
  {
  ; need to update
  ;kvTable[kEdit] := vEdit
    if IsObject(kvTable[kEdit])
    {
      kvTable[kEdit].Insert(vEdit)
    }
    else
    {
      kvTable[kEdit]=Array(vEdit)
    }
  */ 
  ;if id =
  ;{
     ;msgbox addkv
     if isObject(kvTable[kEdit])
     {
      if !ifContain(kvTable[kEdit], vEdit)
        kvTable[kEdit].insert(vEdit)
        dedup(kvTable[kEdit])
     }
     else
     {
      kvTable[kEdit] := Array(vEdit)
     }
  ;}
  ;else
  ;{
    ;fromAdd = true
    ;gosub updKV
  ;}
   
   
   
   
   
  Gosub writeDatFile
  Gosub refreshLV
  if !ErrorLevel 
    SB_SetText("[" . kEdit . " = " . vEdit . "]" . A_Space . added_at . today())
	gosub findAdded_or_Updated
      GuiControl ,,kEdit
      GuiControl ,,vEdit
      GuiControl ,,id
  ;msgbox kEdit, vEdit
  ;ControlFocus, SysListView321
  
Return ;AddKv  

updKV:
  
  ;if kvTable[prv_key] 
  ;  kvTable.Remove(prv_key)
  ;kvTable[kEdit] := vEdit
  id := sepTo2(id)
  ;if !fromAdd
  kvTable[id.1].remove(id.2)
  
  if isObject(kvTable[kEdit])
     {
      if !ifContain(kvTable[kEdit], vEdit)
        kvTable[kEdit].insert(vEdit)
        dedup(kvTable[kEdit])
     }
     else
     {
      kvTable[kEdit] := Array(vEdit)
     }
  

  Gosub writeDatFile
  gosub refreshLV
  gosub findAdded_or_Updated
  GuiControl ,,kEdit
  GuiControl ,,vEdit
  GuiControl ,,id
  SB_SetText("[" . kEdit . " = " . vEdit . "]" . A_Space . updated_at . today())
return ;updKV

delKV:
  id := sepTo2(id)
  kvTable[id.1].remove(id.2)
  Gosub writeDatFile
  Gosub refreshLV
  GuiControl ,,kEdit
  GuiControl ,,vEdit
  GuiControl ,,id
  SB_SetText("[" . kEdit . " = " . vEdit . "]" . A_Space . deleted_at . today())
return ;delKV


5updKV:
  gui, 5:submit
  gui, 5:destroy
  gui, 1: -Disabled 
  gui, 1: show
  ;vEdit := vupdEdit
  Gosub updKV
return ;5updKV


5delKV:
  gui, 5:destroy 
  gui, 1: -Disabled 
  gui, 1: show
  Gosub delKV
return ;5delKV

5cancel:
5GuiClose:
5GuiEscape:
  gui, 5:destroy
  gui, 1: -Disabled
  gui, 1: show
return ;5cancel

writeDatFile:
  FileDelete kv.dat
  if !ErrorLevel
  {
    s = 
	for k, v in kvTable 
    {
	  ;s := s . k . "`t" . v . "`n"
      for i, v0 in v
      {
        s := s . k . "`t" . v0 . "`n"
      }  
	  
	}
	FileAppend, %s%, kv.dat, utf-16
  }
return ;updateDatFile


refreshLV:
  Gui,1:Default
  LV_Delete()
  gosub populateLV
return ;refreshLV

populateLV:
 for k, v in kvTable 
{ 
  for i, e in v
  {
    LV_Add("", k, e, k . "_" . i)
  }
}
return ; popLV


findAdded_or_Updated:
  loop % LV_GetCount()
  {
    LV_GetText(outk, A_Index, 1)
    LV_GetText(outv, A_Index, 2)
   ; MsgBox %outk%, %outv%, %kEdit%, %vEdit%
	If ifEQ(outk, kEdit) && ifEQ(outv, vEdit)
	{
      LV_Modify(A_index, "+Select +Focus Vis")
	  break
	}	
  }
return ;findAdded_or_Updated




makeScript:
  s = 
  (
#SingleInstance force
#Hotstring O
#Hotstring EndChars %trigger%
;#NoTrayIcon
#include inc\funx.ahk
c = 64

  )
/*
  for k,v in kvTable
  {
  ;  s := s . "::" . k . "::" . v . "`n"
    StringReplace v, v, ", "", all
    stringReplace v, v, ``,````, all
    s = %s%::%k%::`nP("%v%", %sound%)`nreturn`n
  }
*/
 for k, v in kvTable
 {
   if v.MaxIndex()>1
   {
    s0 := arrayToString(v)
    s = %s%::%k%::`nvArr := [%s0%]`ngosub i`nmenu, m, DeleteAll`nreturn`n    
   }
   else if v.maxindex()=1
   {
    v1 := v[1]
    StringReplace v1, v1, ", "", all
    stringReplace v1, v1, ``,````, all
    s = %s%::%k%::`n%sendmode%("%v1%", %sound%)`nreturn`n 
   }
 } 

s1 =
(
 i:
  for i,v in vArr
  {
	a := chr(c+i)
	menu , m, add, &`%a`%``t`%v`%, l1
  }
  menu, m, color, white
  ;menu, m, default, 
  menu, m,show, `% A_CaretX, `% A_CaretY+30
 return


l1:
  StringSplit out, A_ThisMenuItem , `%A_Tab`%
  %sendmode%(out2, %sound%)
return
)

s =%s%%s1%

  FileDelete, kv.ahk
  FileAppend, %s% , kv.ahk, utf-16
  Run AutoHotkey.exe "kv.ahk"
return ;makeScript

^k:: 
  Progress ,30, ,%wait_loading%
  ;SplashTextOn ,,, Openging...
  clip:=ClipboardAll
  clipboard=
  send ^c
  clipwait 1.0
  progress 100
  sleep 10
  progress, off
  GuiControl ,,kEdit
  GuiControl ,,vEdit, %Clipboard%
  Gui, Show, Center h440 w460, %myHotStrings_Manager%
  gosub refreshLV
 ; PostMessage, 0x111, 65305,,, kv.ahk - AutoHotkey
 ; TrayTip, %Traytip_suspended_title%, %traytip_suspended_text%, 3,1 
return

^l::
  GuiControl ,,kEdit
  GuiControl ,,vEdit, %Clipboard%
  Gui, Show, Center h440 w460, %myHotStrings_Manager%
  gosub refreshLV
return

^!R::
  gosub Reload
return

#IfWinActive myHotStrings
~Del::
  GuiControlGet, ov, Focus
  if ov = syslistview321
  {
    MsgBox, 4, Delete selected?, Are you sure to delete the selected entry(ies)?
    IfMsgBox, Yes
    {
      ids :=Object()
      RowNumber = 0       ; This causes the first loop iteration to start the search at the top of the list.
      ii = 0
      Loop
      {
        RowNumber := LV_GetNext(RowNumber)  ; Resume the search at the row after that found by the previous iteration.
        if not RowNumber  ; The above returned zero, so there are no more selected rows.
          break
        LV_GetText(idText, RowNumber, 3)
        ;LV_Delete(RowNumber)
        idtext := sepTo2(idText)
        kvTable[idtext.1].remove(idtext.2)
        ii++        
      }
    }
     else
      return
  Gosub writeDatFile
  Gosub refreshLV
  gosub makeScript
  GuiControl ,,kEdit
  GuiControl ,,vEdit
  GuiControl ,,id
  SB_SetText("[" . ii . " entry(ies)]" . A_Space . deleted_at . today())
  }
  return